Skip to content

feat(guardrails): send attached file references with llm-as-judge evaluation - #1082

Merged
apetraru-uipath merged 1 commit into
mainfrom
feat/guardrail-judge-file-support
Sep 17, 2026
Merged

apetraru-uipath merged 1 commit into
mainfrom
feat/guardrail-judge-file-support

Conversation

@apetraru-uipath

@apetraru-uipath apetraru-uipath commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Ready. uipath-platform 0.2.31 is published (UiPath/uipath-python#1895 merged); this branch is rebased onto main, requires uipath-platform>=0.2.31, relocked, and bumped to 0.18.9. 320 guardrail tests pass against the published SDK.

What

Agent-scope and LLM-scope LLM-as-Judge guardrails on low-code agents now forward the run's job attachments to the guardrails backend as references (id, fileName, mimeType), so the judge can evaluate what is in the file rather than its metadata.

  • New agent/guardrails/attachment_refs.py projects state.inner_state.job_attachments into attachment references — no runtime feature flag: the runtime forwards references for every built-in guardrail and every file type whenever the run has attachments (the guardrail's appliesTo = Prompts is the only runtime-side opt-out), and the backend's EnableGuardrailLlmAsJudgeAttachments flag decides whether they are used at all and which validators and types it can inspect (today llm_as_judge, text/pdf/images). Backward compatible: a backend without attachment support ignores the extra property and header (UnmappedMemberHandling = Skip). It never raises: the low-code guardrail node re-raises everything, so a malformed entry must not kill the run.
  • guardrail_nodes.py: the payload generator runs once per evaluation, evaluate_guardrail is offloaded with asyncio.to_thread, and a backend 400 on a request that carried attachments is retried text-only rather than terminating the run.

Out of scope by design: the coded-agent middleware and decorator flavors, and tool scope.

v2 — no SAS resolution in the runtime (commit 51374716)

The first version resolved each attachment to a signed URL via get_blob_file_access_uri_async and sent the URL. The backend now resolves ids itself through Orchestrator (UiPath/Agents#6256), so the runtime forwards references only: no Orchestrator round-trip per file, no credential on the wire, no URL redaction. 320 guardrail tests pass; ruff and ruff format clean; mypy clean in guardrail files (the remaining errors are pre-existing missing-extras imports in chat/_legacy and agent/advanced/code_interpreter.py).

Merge order: UiPath/uipath-python#1895 (merged, published as uipath-platform 0.2.31) first; this PR now depends on that release.

Review fixes (d9d57812)

  • Tool scope excluded. _create_guardrail_node had no scope check and the tool node routes through it, so a tool-scope judge would have shipped file contents on every tool call. Now Agent and LLM scope only, per the product decision.
  • A helix 400 on a request that carried attachments falls back to text-only instead of terminating the run — the backend rejected the file references, which is not the agent's fault. A 400 without attachments still propagates.
  • File names are truncated to the API's 260-character ceiling before forwarding.
  • Dropped metadata["payload"]["attachments"]: nothing consumed it (the Python side creates no evaluation span for built-in guardrails; helix's span already records attachments) and it was never cleared across turns.

Scope selector (06a64b0c)

The judge guardrail gained an optional appliesTo parameter (Prompts / Files / Both) in UiPath/Agents#6256. The backend gates on it as well, but only after the SAS urls are resolved, so reading it here is what actually saves an Orchestrator round-trip per file on a prompts-only guardrail.

Absent, unrecognized, or unreadable keeps files in scope, matching the backend default of Both — silently stopping file scanning for a guardrail whose author never asked for that is the worse direction. The parameter id is matched case-insensitively, as the backend matches it.

Notes for reviewers

attachment_refs.py never raises. The low-code guardrail node re-raises everything it sees, which terminates the agent run — so a transient Orchestrator failure must never escape. Gated on appliesTo only; no feature flag, validator or type filter on the runtime side — the backend flag is the single kill switch.

Two pre-existing bugs fixed along the way, both with regression tests: the payload generator ran twice per evaluation, and the synchronous evaluate_guardrail blocked the event loop (now asyncio.to_thread).

Out of scope by design: the coded-agent middleware and decorator flavors.

Test plan

tests/agent/guardrails/305 passed (baseline 279). tests/cli/ 55, tests/guardrails/ 253 (coded flavors, untouched). ruff, ruff format, mypy (touched files) clean.

Depends on: UiPath/uipath-python#1895 · pairs with UiPath/Agents#6256

🤖 Generated with Claude Code

@apetraru-uipath
apetraru-uipath force-pushed the feat/guardrail-judge-file-support branch 2 times, most recently from 5137471 to 908f604 Compare September 17, 2026 07:44
@apetraru-uipath
apetraru-uipath marked this pull request as ready for review September 17, 2026 07:44
Copilot AI lite review requested due to automatic review settings September 17, 2026 07:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved attachment-reference safety and shared metadata concurrency issues need to be addressed.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds feature-flagged attachment references to low-code LLM-as-Judge guardrail evaluations.

Changes:

  • Projects supported attachments into guarded backend references.
  • Adds asynchronous evaluation and attachment-related 400 fallback.
  • Updates dependencies and expands regression coverage.
File summaries
File Description
uv.lock Relocks updated dependencies.
tests/cli/test_agent_with_guardrails.py Updates test guardrail mocks.
tests/cli/conftest.py Updates guardrail mock signatures.
tests/agent/guardrails/test_guardrail_nodes.py Tests forwarding, fallback, and async evaluation.
tests/agent/guardrails/test_attachment_refs.py Tests reference filtering and scoping.
src/uipath_langchain/agent/guardrails/guardrail_nodes.py Sends references and handles evaluation fallback.
src/uipath_langchain/agent/guardrails/attachment_refs.py Builds feature- and scope-gated attachment references.
pyproject.toml Updates version and platform dependency.
Review details

Suppressed comments (1)

src/uipath_langchain/agent/guardrails/guardrail_nodes.py:248

  • metadata is captured by the node closure and installed as the graph node's metadata, but this path now awaits asyncio.to_thread. Concurrent invocations of the same compiled graph can therefore interleave and overwrite metadata["payload"], causing one run's observability payload to be reported for another run. Make the payload metadata invocation-scoped (or otherwise protect/copy it) rather than mutating this shared dictionary.
                # Generate and store payload for observability. Generated once and passed
                # down: it used to run again inside _evaluate_builtin_guardrail.
                payload = payload_generator(state)
                if execution_stage == ExecutionStage.PRE_EXECUTION:
                    metadata["payload"]["input"] = payload
                else:
                    metadata["payload"]["output"] = payload
  • Files reviewed: 7/8 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/uipath_langchain/agent/guardrails/attachment_refs.py Outdated
@apetraru-uipath
apetraru-uipath force-pushed the feat/guardrail-judge-file-support branch from f87bc01 to 3da8afc Compare September 17, 2026 08:18
Comment thread src/uipath_langchain/agent/guardrails/attachment_refs.py Outdated
Comment thread src/uipath_langchain/agent/guardrails/attachment_refs.py Outdated
Comment thread src/uipath_langchain/agent/guardrails/attachment_refs.py Outdated
Comment thread src/uipath_langchain/agent/guardrails/guardrail_nodes.py
@apetraru-uipath
apetraru-uipath force-pushed the feat/guardrail-judge-file-support branch 2 times, most recently from 842d463 to e48ced5 Compare September 17, 2026 13:50
…luation

Agent-scope and LLM-scope built-in guardrails on low-code agents now forward
the run's job attachments to the guardrails backend, so a guardrail can
evaluate what is in a file rather than the serialized metadata that currently
lands in the prompt.

- New agent/guardrails/attachment_refs.py projects state.inner_state.job_attachments
  into references (id, file name, mime type). The backend resolves the id through
  Orchestrator; the runtime makes no network call and never resolves a URL.
  No feature flag, validator or file-type filter on the runtime side: the
  backend's EnableGuardrailLlmAsJudgeAttachments flag decides whether the
  references are used at all, and the backend decides which validators and
  types it can inspect (today: llm_as_judge, text/pdf/images). The guardrail's
  appliesTo parameter (Prompts) is the only runtime-side opt-out. At most five
  references. Never raises: entries are built one by one and a malformed one is
  skipped without consuming a slot. Backward compatible: a backend without
  attachment support ignores the extra property and header.
- guardrail_nodes.py: payload generated once per evaluation, evaluate_guardrail
  offloaded to a thread, attachments resolved at Agent and LLM scope only, and a
  400 on a request carrying attachments is retried without them so a file can
  never fail the run.
- Requires uipath-platform>=0.2.31 (GuardrailAttachment); version 0.18.9.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@apetraru-uipath
apetraru-uipath force-pushed the feat/guardrail-judge-file-support branch from e48ced5 to 3779e92 Compare September 17, 2026 14:24
@sonarqubecloud

Copy link
Copy Markdown

@apetraru-uipath
apetraru-uipath merged commit 09df3b1 into main Sep 17, 2026
48 checks passed
@apetraru-uipath
apetraru-uipath deleted the feat/guardrail-judge-file-support branch September 17, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants